#ifndef MEMORYPOOL_H
#define MEMORYPOOL_H

#include <atomic>
#include <cstddef>
#include <mutex>
#include <QDebug>
#include <QObject>
#include "poolinfo.h"

#define MEMORY_POOL_NUM 64
#define SLOT_BASE_SIZE 8
#define MAX_SLOT_SIZE 512
#define BLOCK_SIZE 4096

/**
 * @brief 内存池的槽结构体
 * 用于串联空闲链表，实际分配的内存以Slot为单位切分
 */
struct Slot
{
    std::atomic<Slot*> next;    // 原子指针，用于串联空闲链表
};

/**
 * @brief 内存池类
 * 管理内存池的初始化、内存分配和释放
 */
class MemoryPool
{
public:
    MemoryPool(size_t BlockSize = BLOCK_SIZE);
    ~MemoryPool();

    void init(size_t);

    void* allocate();

    void deallocate(void*);


    // 添加统计接口 给HashBucket使用
    int getSlotSize() const;
    int getBlockCnt() const;
    int getFreeSlotCnt() const;
    int getUsedSlotCnt() const;
    int getTotalSlotCnt() const;

private:
    void allocateNewBlock();
    size_t padPointer(char* p, size_t align);

    // 使用CAS操作进行无锁入队和出队
    bool pushFreeList(Slot* slot);
    Slot* popFreeList();
private:
    int                 BlockSize_; // 内存块大小
    int                 SlotSize_; // 槽大小
    Slot*               firstBlock_; // 指向内存池管理的首个实际内存块
    Slot*               curSlot_; // 指向当前未被使用过的槽
    // 仅有freeList_是原子类型，因为多个线程同时分配和释放内存，竞争激烈，使用原子操作保证线程安全
    std::atomic<Slot*>  freeList_; // 指向空闲的槽(被使用过后又被释放的槽)
    Slot*               lastSlot_; // 作为当前内存块中最后能够存放元素的位置标识(超过该位置需申请新的内存块)
    //std::mutex          mutexForFreeList_; // 保证freeList_在多线程中操作的原子性
    std::mutex          mutexForBlock_; // 保证多线程情况下避免不必要的重复开辟内存导致的浪费行为
 
    std::atomic<int>    totalSlotCnt_;
    std::atomic<int>    usedSlotCnt_;
};

class HashBucket : public QObject
{
    Q_OBJECT
public:
    // 初始化内存池
    static void initMemoryPool();
    static MemoryPool& getMemoryPool(int index);
    static PoolStatus getPoolStatus(int index);

    static int getPoolIdxBySize(size_t size)
    {
        return ((size + 7) / SLOT_BASE_SIZE) - 1;
    }
    // 选择合适的内存池分配内存
    static void* useMemory(size_t size)
    {
        if (size <= 0) return nullptr;
        // 大于512字节的内存，则使用new
        if (size > MAX_SLOT_SIZE) return operator new(size);

        // 相当于size / 8 向上取整（因为分配内存只能大不能小）
        return getMemoryPool(getPoolIdxBySize(size)).allocate();
    }

    // 释放内存
    static void freeMemory(void* ptr, size_t size)
    {
        if (!ptr) return;
        if (size > MAX_SLOT_SIZE) return operator delete(ptr);
        getMemoryPool(getPoolIdxBySize(size)).deallocate(ptr);
    }
    template<typename T, typename... Args> 
    friend T* newElement(Args&&... args);
    
    template<typename T>
    friend void deleteElement(T* p);
};

template<typename T, typename... Args>
T* newElement(Args&&... args)
{
    T* p = nullptr;
    // 根据元素大小选取合适的内存池分配内存
    if ((p = reinterpret_cast<T*>(HashBucket::useMemory(sizeof(T)))) != nullptr)
        // 在分配的内存上构造对象
        new(p) T(std::forward<Args>(args)...);

    return p;
}

template<typename T>
void deleteElement(T* p)
{
    // 对象析构
    if (p)
    {
        p->~T();
        // 内存回收
        HashBucket::freeMemory(reinterpret_cast<void*>(p), sizeof(T));
    }
}
#endif // MEMORYPOOL_H
